<!DOCTYPE html>
<html>
<head>
    <title>NAT Proxy 状态</title>
    <meta charset="UTF-8">
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
    <style>
        [v-cloak] { display: none; }
        .fade-enter-active, .fade-leave-active {
            transition: opacity 0.3s ease;
        }
        .fade-enter-from, .fade-leave-to {
            opacity: 0;
        }
        .log-container {
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 0.9rem;
            line-height: 1.4;
            white-space: pre-wrap;
            word-wrap: break-word;
        }
        .status-badge {
            animation: pulse 2s infinite;
        }
        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }
    </style>
</head>
<body class="bg-gray-100">
    <div id="app" v-cloak class="min-h-screen">
        <div class="container mx-auto px-4 py-8">
            <header class="mb-8">
                <h1 class="text-3xl font-bold text-gray-800 mb-2">NAT Proxy 状态监控</h1>
                <div class="flex items-center">
                    <div class="status-badge w-3 h-3 rounded-full mr-2"
                         :class="{'bg-green-500': status.running, 'bg-red-500': !status.running}">
                    </div>
                    <span class="text-sm text-gray-600">
                        {{ status.running ? '运行中' : '已停止' }}
                    </span>
                </div>
            </header>

            <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
                <!-- 状态卡片 -->
                <div class="bg-white rounded-lg shadow p-6">
                    <h2 class="text-xl font-semibold text-gray-800 mb-4">系统状态</h2>
                    <div class="space-y-2">
                        <div class="flex justify-between">
                            <span class="text-gray-600">运行时间</span>
                            <span class="text-gray-800">{{ status.uptime || '-' }}</span>
                        </div>
                    </div>
                </div>

                <!-- 配置卡片 -->
                <div class="bg-white rounded-lg shadow p-6">
                    <h2 class="text-xl font-semibold text-gray-800 mb-4">当前配置</h2>
                    <div class="space-y-2" v-if="config">
                        <div class="flex justify-between">
                            <span class="text-gray-600">服务器地址</span>
                            <span class="text-gray-800">{{ config.client.server_addr }}</span>
                        </div>
                        <div class="flex justify-between">
                            <span class="text-gray-600">本地端口</span>
                            <span class="text-gray-800">{{ config.client.local_port }}</span>
                        </div>
                        <div class="flex justify-between">
                            <span class="text-gray-600">客户端ID</span>
                            <span class="text-gray-800">{{ config.client.client_id }}</span>
                        </div>
                        <div class="flex justify-between">
                            <span class="text-gray-600">心跳间隔</span>
                            <span class="text-gray-800">{{ config.client.heartbeat_interval }}秒</span>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 日志部分 -->
            <div class="bg-white rounded-lg shadow">
                <div class="p-6">
                    <div class="flex justify-between items-center mb-4">
                        <h2 class="text-xl font-semibold text-gray-800">系统日志</h2>
                        <div class="space-x-2">
                            <button @click="clearLogs" 
                                    class="px-3 py-1 text-sm bg-gray-200 hover:bg-gray-300 rounded">
                                清空
                            </button>
                            <button @click="refreshLogs" 
                                    class="px-3 py-1 text-sm bg-blue-500 hover:bg-blue-600 text-white rounded">
                                刷新
                            </button>
                        </div>
                    </div>
                    <div class="border rounded-lg">
                        <div class="flex border-b">
                            <button @click="activeTab = 'client'"
                                    :class="{'bg-gray-100': activeTab === 'client'}"
                                    class="flex-1 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50">
                                客户端日志
                            </button>
                            <button @click="activeTab = 'response'"
                                    :class="{'bg-gray-100': activeTab === 'response'}"
                                    class="flex-1 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50">
                                响应日志
                            </button>
                        </div>
                        <div class="p-4 bg-gray-50 max-h-96 overflow-auto log-container">
                            <template v-if="activeTab === 'client'">
                                <div v-for="(log, index) in logs.client_logs" :key="'client-'+index"
                                     class="text-sm text-gray-800">
                                    {{ log }}
                                </div>
                            </template>
                            <template v-else>
                                <div v-for="(log, index) in logs.response_logs" :key="'response-'+index"
                                     class="text-sm text-gray-800">
                                    {{ log }}
                                </div>
                            </template>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        const API_BASE = 'http://localhost:9999/api';
        const WS_URL = 'ws://localhost:9999/ws';

        const app = Vue.createApp({
            data() {
                return {
                    status: {
                        running: false,
                        uptime: ''
                    },
                    config: null,
                    logs: {
                        client_logs: [],
                        response_logs: []
                    },
                    activeTab: 'client',
                    ws: null,
                    wsReconnectTimer: null
                }
            },
            methods: {
                // 初始数据加载方法
                async loadInitialData() {
                    try {
                        // 加载状态
                        const statusResp = await fetch(`${API_BASE}/status`);
                        if (statusResp.ok) {
                            const data = await statusResp.json();
                            this.status = data;
                            this.config = data.config;
                        }

                        // 加载日志
                        const logsResp = await fetch(`${API_BASE}/logs`);
                        if (logsResp.ok) {
                            this.logs = await logsResp.json();
                        }
                    } catch (error) {
                        console.error('初始数据加载失败:', error);
                    }
                },

                // WebSocket 相关方法
                setupWebSocket() {
                    if (this.ws) {
                        this.ws.close();
                    }

                    this.ws = new WebSocket(WS_URL);
                    
                    this.ws.onmessage = (event) => {
                        try {
                            const update = JSON.parse(event.data);
                            switch (update.type) {
                                case 'status':
                                    this.status = update.data;
                                    this.config = update.data.config;
                                    break;
                                case 'logs':
                                    this.logs = update.data;
                                    break;
                            }
                        } catch (error) {
                            console.error('处理消息失败:', error);
                        }
                    };

                    this.ws.onclose = () => {
                        console.log('WebSocket 连接已断开，尝试重新连接...');
                        if (this.wsReconnectTimer) {
                            clearTimeout(this.wsReconnectTimer);
                        }
                        this.wsReconnectTimer = setTimeout(() => {
                            this.setupWebSocket();
                        }, 3000);
                        
                        // 更新状态为断开
                        this.status.running = false;
                    };

                    this.ws.onerror = (error) => {
                        console.error('WebSocket 错误:', error);
                        this.status.running = false;
                    };

                    this.ws.onopen = () => {
                        console.log('WebSocket 连接已建立');
                        // 立即请求一次状态更新
                        this.ws.send(JSON.stringify({ type: 'refresh' }));
                    };
                },

                clearLogs() {
                    this.logs = {
                        client_logs: [],
                        response_logs: []
                    };
                },

                refreshLogs() {
                    // 发送刷新请求到服务器
                    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
                        this.ws.send(JSON.stringify({ type: 'refresh' }));
                    }
                }
            },
            async mounted() {
                // 先加载初始数据
                await this.loadInitialData();
                // 然后建立 WebSocket 连接
                this.setupWebSocket();
            },
            beforeUnmount() {
                if (this.ws) {
                    this.ws.close();
                }
                if (this.wsReconnectTimer) {
                    clearTimeout(this.wsReconnectTimer);
                }
            }
        });

        app.mount('#app');
    </script>
</body>
</html> 